#include "virt_kb.h"
#include <stdlib.h>

/* 键盘事件回调函数 */
static void kb_event_cb(lv_event_t *e)
{
    lv_obj_t *kb = lv_event_get_target(e);
    virt_kb_t *virt_kb = lv_event_get_user_data(e);
    
    if (virt_kb && virt_kb->ta) {
        lv_keyboard_def_event_cb(e);
        if (lv_event_get_code(e) == LV_EVENT_CANCEL) {
            virt_kb_hide(virt_kb);
        }
    }
}

/* 文本区域事件回调函数 */
static void ta_event_cb(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t *ta = lv_event_get_target(e);
    virt_kb_t *virt_kb = lv_event_get_user_data(e);
    
    if (code == LV_EVENT_FOCUSED) {
        if (virt_kb) {
            virt_kb_show(virt_kb, ta);
        }
    } else if (code == LV_EVENT_DEFOCUSED) {
        if (virt_kb) {
            virt_kb_hide(virt_kb);
        }
    }else if(code == LV_EVENT_READY || code == LV_EVENT_CANCEL) {
        if (virt_kb) {
            virt_kb_hide(virt_kb);
        }
    }
}

/**
 * 获取对象的顶级父控件
 * @param obj 需要获取顶级父控件的对象
 * @return 返回顶级父控件，如果对象为NULL则返回NULL
 */
static lv_obj_t *get_top_parent(lv_obj_t *obj)
{
    if (!obj) {
        return NULL;
    }

    lv_obj_t *parent = obj;
    lv_obj_t *last_parent = NULL;

    /* 循环向上遍历父对象链，直到找到最顶层的父对象 */
    while (parent) {
        last_parent = parent;
        parent = lv_obj_get_parent(parent);
        
        /* 如果父对象是屏幕对象，则返回当前对象 */
        if (parent == lv_scr_act()) {
            return last_parent;
        }
    }

    return last_parent;
}

virt_kb_t *virt_kb_init(void)
{
    virt_kb_t *kb = (virt_kb_t *)malloc(sizeof(virt_kb_t));
    if (!kb) {
        return NULL;
    }
    
    /* 创建键盘对象，键盘必须在所有顶层窗口创建后再创建，否则无法弹出 */
    kb->kb = lv_keyboard_create(lv_scr_act());
    if (!kb->kb) {
        free(kb);
        return NULL;
    }


    /* 设置键盘属性 */
    lv_keyboard_set_mode(kb->kb, LV_KEYBOARD_MODE_TEXT_LOWER);
    lv_obj_add_flag(kb->kb, LV_OBJ_FLAG_HIDDEN);
    lv_obj_clear_flag(kb->kb, LV_OBJ_FLAG_CLICK_FOCUSABLE);
 
    /* 设置键盘样式 */
    lv_obj_set_size(kb->kb, LV_PCT(100), LV_PCT(50));
    lv_obj_align(kb->kb, LV_ALIGN_BOTTOM_MID, 0, 0);
    lv_obj_set_style_bg_opa(kb->kb, LV_OPA_100, 0);
    
    /* 注册键盘事件回调 */
    //lv_obj_add_event_cb(kb->kb, kb_event_cb, LV_EVENT_ALL, kb);
 
    kb->ta = NULL;
    kb->is_visible = false;
    
    return kb;
}

void virt_kb_show(virt_kb_t *kb, lv_obj_t *ta)
{
    if (!kb || !ta) {
        return;
    }
    
    /* 如果键盘已经显示且关联的是同一个文本框，则不需要重新显示 */
    if (kb->is_visible && kb->ta == ta) {
        return;
    }
 
    /* 设置键盘关联的文本框 */
    kb->ta = ta;
    lv_keyboard_set_textarea(kb->kb, ta);
    
    /* 注册文本框事件回调 */
    lv_obj_add_event_cb(ta, ta_event_cb, LV_EVENT_ALL, kb);
    
    /* 显示键盘 */
    lv_obj_clear_flag(kb->kb, LV_OBJ_FLAG_HIDDEN);

    /* 如果键盘不是在其他顶层窗口创建后再创建，需要使用这个函数使其置顶 */
    //lv_obj_move_foreground(kb->kb);
    
    /* 调整文本框位置，避免被键盘遮挡 */
    lv_obj_update_layout(ta);
    lv_coord_t kb_height = lv_obj_get_height(kb->kb);
    lv_coord_t screen_height = lv_disp_get_ver_res(NULL);
    
    /* 获取文本框相对于屏幕的绝对坐标 */
    lv_area_t coords;
    lv_obj_get_coords(ta, &coords);
    
    if (coords.y2 > screen_height - kb_height) {
        lv_obj_set_height(get_top_parent(ta), LV_VER_RES - lv_obj_get_height(kb->kb));
        lv_obj_scroll_to_view_recursive(ta, LV_ANIM_OFF);
    }
    
    kb->is_visible = true;
}

void virt_kb_hide(virt_kb_t *kb)
{
    if (!kb || !kb->is_visible) {
        return;
    }
    
    if (kb->ta) {
        lv_obj_set_height(get_top_parent(kb->ta), LV_VER_RES);
    }  

    /* 隐藏键盘 */
    lv_obj_add_flag(kb->kb, LV_OBJ_FLAG_HIDDEN);
    kb->is_visible = false;
    
    /* 清除文本框关联 */
    if (kb->ta) {
        lv_obj_remove_event_cb_with_user_data(kb->ta, ta_event_cb, kb);
        lv_indev_reset(NULL, kb->ta);   /*To forget the last clicked object to make it focusable again*/
        kb->ta = NULL;
    }
}

void virt_kb_destroy(virt_kb_t *kb)
{
    if (!kb) {
        return;
    }
    
    /* 隐藏并删除键盘对象 */
    if (kb->kb) {
        lv_obj_del(kb->kb);
    }
    
    /* 释放内存 */
    free(kb);
}
